package com.jiunuan.live.user.provider.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.jiunuan.live.common.interfaces.enums.CommonstatusEnum;
import com.jiunuan.live.common.interfaces.utils.ConvertBeanUtils;
import com.jiunuan.live.common.interfaces.utils.DESUtils;
import com.jiunuan.live.framework.redis.starter.key.UserProviderCacheKeyBuilder;
import com.jiunuan.live.id.generate.enums.IdTypeEnum;
import com.jiunuan.live.id.generate.interfaces.IdGenerateRpc;
import com.jiunuan.live.user.dto.UserDTO;
import com.jiunuan.live.user.dto.UserLoginDTO;
import com.jiunuan.live.user.dto.UserPhoneDTO;
import com.jiunuan.live.user.provider.dao.mapper.IUserPhoneMapper;
import com.jiunuan.live.user.provider.dao.po.UserPhonePO;
import com.jiunuan.live.user.provider.service.IUserPhoneService;
import com.jiunuan.live.user.provider.service.IUserService;
import jakarta.annotation.Resource;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
public class UserPhoneServiceImpl implements IUserPhoneService {
    @Resource
    private IUserPhoneMapper userPhoneMapper;
    @Resource
    private RedisTemplate<String,Object> redisTemplate;
    @Resource
    private UserProviderCacheKeyBuilder cacheKeyBuilder;
    @Resource
    private IUserService userService;
    @DubboReference
    private IdGenerateRpc idGenerateRpc;

    @Override
    public UserLoginDTO login(String phone) {
        // phone 不为空
        if(phone == null){
            return null;
        }
        // 是否注册过
        UserPhoneDTO userPhoneDTO = queryByPhone(phone);
        //如果注册过，返回userId
        if(userPhoneDTO != null){
            return UserLoginDTO.loginSuccess(userPhoneDTO.getUserId());
        }
        // 如果没注册过，生成user信息，插入手机记录，绑定userId
        return registerAndLogin(phone);
    }

    /**
     * 注册并登录用户
     * 本函数主要负责用户的注册和登录流程，包括生成用户ID，设置用户初始信息，绑定电话号码，并返回登录所需的信息
     *
     * @param phone 用户的电话号码，用于注册时绑定
     * @return UserLoginDTO 返回用户的登录信息，用户ID
     */
    private UserLoginDTO registerAndLogin(String phone){
        // 生成用户ID
        Long userId = idGenerateRpc.getUnSeqId(IdTypeEnum.USER_ID.getCode());
        // 创建用户对象并设置初始信息
        UserDTO userDTO = new UserDTO();
        userDTO.setNickName("酒暖用户-"+userId);
        userDTO.setUserId(userId);
        userService.insertOne(userDTO);
        // 绑定电话号码
        UserPhonePO userPhonePO = new UserPhonePO();
        userPhonePO.setUserId(userId);
        userPhonePO.setPhone(DESUtils.encrypt(phone));
        userPhonePO.setStatus(CommonstatusEnum.VALID_STATUS.getCode());
        userPhoneMapper.insert(userPhonePO);
        redisTemplate.delete(cacheKeyBuilder.buildUserPhoneObjKey(phone));
        // 返回登录信息
        return UserLoginDTO.loginSuccess(userId);
    }


    /**
     * 查询根据手机号用户信息
     * @param phone
     * @return
     */
    @Override
    public UserPhoneDTO queryByPhone(String phone) {
        if(StringUtils.isEmpty(phone)){
            return null;
        }
        String redisKey = cacheKeyBuilder.buildUserPhoneObjKey(phone);
        UserPhoneDTO userPhoneDTO = (UserPhoneDTO) redisTemplate.opsForValue().get(redisKey);
        // 如果redis中存在，直接返回
        if(userPhoneDTO!=null){
            // 如果userId为空，说明redis缓存击穿了，为缓存.
            if(userPhoneDTO.getUserId() == null){
                return null;
            }
            return userPhoneDTO;
        }
        userPhoneDTO = this.queryByPhoneFromDB(phone);
        if(userPhoneDTO!=null){
            // 解密手机号
            userPhoneDTO.setPhone(DESUtils.decrypt(userPhoneDTO.getPhone()));
            // 补充到redis
            redisTemplate.opsForValue().set(redisKey,userPhoneDTO,30, TimeUnit.MINUTES);
            return userPhoneDTO;
        }
        // 空id打到DB层，造成缓存击穿，使用控制缓存方法
        userPhoneDTO = new UserPhoneDTO();
        redisTemplate.opsForValue().set(redisKey,userPhoneDTO,5, TimeUnit.MINUTES);
        return null;
    }

    /**
     * 从数据库查询用户信息
     * @param phone
     * @return
     */
    private UserPhoneDTO queryByPhoneFromDB(String phone){
        LambdaQueryWrapper<UserPhonePO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(UserPhonePO::getPhone,DESUtils.encrypt(phone));
        queryWrapper.eq(UserPhonePO::getStatus, CommonstatusEnum.VALID_STATUS.getCode());
        queryWrapper.last("limit 1");
        return ConvertBeanUtils.convert(userPhoneMapper.selectOne(queryWrapper),UserPhoneDTO.class);
    }

    /**
     * 根据用户ID查询电话号码列表
     *
     * @param userId 用户ID
     * @return 用户电话号码列表
     */
    @Override
    public List<UserPhoneDTO> queryByUserId(Long userId) {
        // 检查用户ID是否有效，小于10000的ID被认为是无效的
        if(userId==null||userId<10000){
            return Collections.emptyList();
        }
        // 构建Redis中的用户电话列表键
        String redisKey = cacheKeyBuilder.buildUserPhoneListKey(userId);
        // 从Redis中获取用户电话列表
        List<Object> userPhoneList = redisTemplate.opsForList().range(redisKey,0,-1);
        // 检查获取的列表是否为空
        if(!CollectionUtils.isEmpty(userPhoneList)){
            // 如果列表中的第一个元素的用户ID为空，表示之前查询到的是空值，返回空列表
            if (((UserPhoneDTO)userPhoneList.get(0)).getUserId() == null) {
                return Collections.emptyList();
            }
            // 将从Redis中获取的数据转换为正确的类型并返回
            return userPhoneList.stream().map(x -> (UserPhoneDTO) x).collect(Collectors.toList());
        }
        // 如果Redis中没有数据，从数据库中查询用户电话列表
        List<UserPhoneDTO> userPhoneDTOs = this.queryByUserIdFromDB(userId);
        // 如果从数据库查询到的数据不为空
        if(!CollectionUtils.isEmpty(userPhoneList)){
            // 解密电话号码
            userPhoneDTOs.stream().forEach(x -> x.setPhone(DESUtils.decrypt(x.getPhone())));
            // 将数据存入Redis列表的左侧
            redisTemplate.opsForList().leftPushAll(redisKey,userPhoneDTOs.toArray());
            // 设置Redis键的过期时间为30分钟
            redisTemplate.expire(redisKey,30, TimeUnit.MINUTES);
            return userPhoneDTOs;
        }
        // 如果数据库中也没有数据，创建一个空的用户电话DTO并存入Redis，防止缓存击穿
        userPhoneDTOs = Arrays.asList(new UserPhoneDTO());
        redisTemplate.opsForList().leftPush(redisKey,new UserPhoneDTO());
        redisTemplate.expire(redisKey,5, TimeUnit.MINUTES);
        return userPhoneDTOs;
    }


    /**
     * 根据用户id查询记录
     * @param userId
     * @return
     */
    private List<UserPhoneDTO> queryByUserIdFromDB(Long userId) {
        LambdaQueryWrapper<UserPhonePO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(UserPhonePO::getUserId,userId);
        queryWrapper.eq(UserPhonePO::getStatus, CommonstatusEnum.VALID_STATUS.getCode());
        queryWrapper.last("limit 1");
        return ConvertBeanUtils.convertList(userPhoneMapper.selectList(queryWrapper),UserPhoneDTO.class);
    }
}
